const { toLog } = require("./common/common");
const moment = require('moment');
const libcu = require("libcu");
// 数据库锁
class Lock {
    constructor() {
        this.lock = {
            line: {},
            table: {},
        };     //数据库锁   分行锁和表锁  结构为 table : {database : {table: tableName}}
        setInterval(async () => {
            this.releaseLock();
        }, ini.db.checkLockTime * 1000);
    }

    //得到锁  line为后期可选项  set  0-加锁 1-解开锁
    async getLock(dbName, tableName, set,sign,line) {
        if(!dbName || ! tableName || !sign) {
            toLog(`加解锁参数缺失${dbName},table = ${tableName} sign = ${sign}`);
            throw ("UNKNOWN_ERROR");
        }
        let timeOut = ini.db.lockTimeOut * 1000 || 3000;
        //尝试次数超过预设值就取10
        let tryTime = (ini.db.lockTryTime > 10 && ini.db.lockTryTime < 100) ? ini.db.lockTryTime : 10;
        let perTime = timeOut / tryTime; //得到一个尝试时间
        toLog('this.lock = ',this.lock);
        for (let i = 0; i < tryTime; i++) {
            //后期实现行锁
            //set true-加锁 false-只得到锁
            if(set == 0) {
                //目前的表存在锁
                if(this.lock.table[dbName] && this.lock.table[dbName][tableName]) {
                    //如果要加锁 不管有没有解开锁 怎么都是得等的
                    toLog(`${dbName}的${tableName}目前为加锁状态`);
                    await libcu.tools.sleep(perTime);           //等待
                } else {
                    if (!this.lock.table[dbName]) {
                        this.lock.table[dbName] = {};
                    }
                        this.lock.table[dbName][tableName] = {
                            sign,
                            createTime: moment().valueOf(),
                        }
                        toLog(`成功得到${dbName}-${tableName} 并加锁`);
                    return;
                }
            } else if (set == 1) {
                if (this.lock.table[dbName] && this.lock.table[dbName][tableName]) {
                    if(this.lock.table[dbName][tableName].sign == sign) {
                        //如果是自身上的锁则直接解开
                        delete this.lock.table[dbName][tableName];
                        toLog(`成功解锁${dbName}-${tableName}`);
                        return;
                    }
                    toLog(`${dbName}的${tableName}目前为加锁状态`);
                    await libcu.tools.sleep(perTime);           //等待
                } 
            } else {
                //大家都是开发不可能发生这种错误的
                toLog("getLock传参错误");
                throw ('UNKNOWN_ERROR');
            }
        }
        toLog(`得到${dbName}-${tableName}锁超时`);
        throw ('GET_LOCK_FAILED');

    }


    //自动释放锁防止数据库死锁
    async releaseLock() {
        let now = moment().valueOf();
        let releaseLockTime = ini.db.releaseLockTime;
        releaseLockTime = releaseLockTime > ini.db.checkLockTime ? releaseLockTime : ini.db.checkLockTime;
        for(let key in this.lock.table) {
            let tables = this.lock.table[key];
            for(let subKey in tables) {
                let times = tables[subKey];
                toLog("moment(now).diff(moment(times),'seconds') = ",moment(now).diff(moment(times),'seconds'));
                toLog("releaseLockTime = ",releaseLockTime);
                if(moment(now).diff(moment(times),'seconds') > releaseLockTime) {
                    toLog(`自动释放了锁 key = ${subKey}:`,tables[subKey]);
                    delete tables[subKey];
                } 
            }
        }
    }
}

module.exports = Lock;